Next | Prev | Up | Top | Contents | Index

Mutual Exclusion Macros

The macros for mutual exclusion defined in net/if.h are listed in Table 16-2.

Mutual Exclusion Macros for ifnet Drivers
Macro PrototypePurpose
IFNET_LOCK(ifp, s)Get exclusive use of the structure *ifp. splimp() is called to raise the interrupt level if necessary, and the returned value is saved in s.
IFNET_UNLOCK(ifp,s)Release use of *ifp, and return to interrupt level s.
IFNET_LOCKNOSPL(ifp)Get exclusive use of the structure *ifp, but do not call splimp() (the driver knows it is already at the appropriate level.)
IFNET_UNLOCKNOSPL(ifp)Release use of *ifp after use of IFNET_LOCKNOSPL.
IFNET_ISLOCKED(ifp)Test whether *ifp is locked.
IFQ_LOCK(ifq)Get exclusive use of an input queue *ifq.
IFQ_UNLOCK(ifq)Release use of *ifq.
IF_ENQUEUE(ifq, mp)Lock the queue *ifq; post the mbuf *mp; release the queue.
IF_ENQUEUE_NOLOCK(ifq,mp)Post the mbuf *mp without locking.

The variables used in Table 16-2 are as follows:

ifp Address of a struct ifnet to be used exclusively.
s Integer variable to store the current interrupt mask level.
ifq Address of a struct ifqueue to be posted.
mp Address of a struct mbuf to be posted.


Macro Use

The TCP/IP protocol stack automatically acquires the ifnet structure before calling a network driver routine through that structure. Thus the driver's init(), stop(), start(), output(), and ioctl() functions do not need to use IFNET_LOCK or IFNET_UNLOCK. Look for expressions

ASSERT(IFNET_ISLOCKED(ifp));

in the example driver ("Example ifnet Driver") to see places where this is the case. Explicit use of IFNET_LOCK is needed in the interrupt handler.


Input Queueing Example

Example 16-1 displays a code fragment of an interrupt handler that queues an input packet pointed to by m onto the IP input queue. The function schednetisr() is called to schedule processing of that packet. The code is assumed to be already at splimp().

Example 16-1 : Input Queueing Using Locking Macros

{
...
    ifq = &ipintrq; /* the ip protocol queue */
 /*
 * If queue is full, we drop the packet.
 */
    IFQ_LOCK(ifq);
    if (IF_QFULL(ifq)) {
       m_freem(m);
       IF_DROP(ifq);
       IFQ_UNLOCK(ifq);
       return(-1);
    }
    IF_ENQUEUE_NOLOCK(ifq, m);
    schednetisr(NETISR_IP); /* schedule ip interrupt */
    IFQ_UNLOCK(ifq);
    return(0);
}

Interrupt Handler Example

Example 16-2 displays the skeleton of an Ethernet interrupt handler.

Example 16-2 : Interrupt Handling Using Locking Macros

/*
 * Ethernet interface interrupt.
 */
if_etintr(int unit)
{
 ETIO io;
 struct et_info *ei;
 register int s = splimp(); /* get the spin lock */

 ASSERT(unit == 0);
 ei = &et_info;
 io = ei->ei_io;

 if (io == 0) { /* ignore early interrupts */
     printf("et0: early interrupt\n");
     splx(s);
     return 1;
 }
 IFNET_LOCKNOSPL(&ei->ei_if);
 et_poll(ei);
 IFNET_UNLOCKNOSPL(&ei->ei_if);
 splx(s);
} 

Next | Prev | Up | Top | Contents | Index